package priv.wangy.micro.common.po.valid.validator;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.util.CollectionUtils;
import priv.wangy.micro.common.po.valid.ContList;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangjq
 * @since 2024-03-29
 */
@SuppressWarnings({"rawtypes"})
public class ContListValidator implements ConstraintValidator<ContList, List<?>> {

    private int interval;

    private boolean empty;

    private Class<? extends Comparable> sortable;

    int head;

    private Class<?>[] ctorClazz;

    private String[] ctorField;

    @Override
    public void initialize(ContList constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
        interval = constraintAnnotation.interval();
        empty = constraintAnnotation.empty();
        sortable = constraintAnnotation.sortable();
        head = constraintAnnotation.head();
        ctorClazz = constraintAnnotation.ctorClazz();
        ctorField = constraintAnnotation.ctorField();
    }

    private List<Object> sortList(List<?> list) throws NoSuchFieldException, IllegalAccessException {
        List<Object> sortList = new ArrayList<>();
        int l = ctorClazz.length;
        for (Object obj : list) {
            int i = 0;
            Object tgt = obj;
            while (i < l) {
                Field field = ctorClazz[i].getDeclaredField(ctorField[i]);
                field.setAccessible(true);
                tgt = field.get(tgt);
                i++;
            }
            if (!sortable.isInstance(tgt)) {
                throw new RuntimeException("The definition of object structure is incomplete");
            }
            sortList.add(tgt);
        }
        return sortList;
    }

    @Override
    public boolean isValid(List<?> list, ConstraintValidatorContext constraintValidatorContext) {
        if (CollectionUtils.isEmpty(list)) {
            return empty;
        }
        if (list.size() == 1) {
            return true;
        }

        if (ctorField.length != ctorClazz.length) {
            throw new RuntimeException("The definition of object structure is incomplete");
        }

        try {
            List<Object> sortList = sortList(list).stream().sorted().toList();
            if (!CollectionUtils.isEmpty(sortList)) {
                if (head >= 0) {
                    Object obj = sortList.get(0);
                    if (obj instanceof Number && head != ((Number) obj).intValue()) {
                        return false;
                    }
                    if (obj instanceof String && head != Integer.parseInt((String) obj)) {
                        return false;
                    }
                }

                Method method = sortable.getMethod("compareTo", Object.class);
                method.setAccessible(true);
                for (int i = 1; i < sortList.size(); i++) {
                    Comparable<?> comparable = (Comparable<?>) sortable.cast(sortList.get(i));
                    if ((int) method.invoke(comparable, sortList.get(i - 1)) != interval) {
                        return false;
                    }
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        return true;
    }

}
